package com.wakyde.collection;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

public class Demo01 {
    public static void main(String[] args) {
        // 线程不安全的集合有哪些？
        // 1. HashSet
        HashSet<String> set = new HashSet<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
        // 2. HashMap
        // 3. ArrayList
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

        // 怎么解决呢？
//        dealArrayListConcurrent();
//        dealHashSetConcurrent();
        dealHashMapConcurrent();

    }

    /**
     * ArrayList解决线程安全问题的方法  三种
     * 使用Vector 缺点：并发性能比较差
     * 使用Collections.synchronizedList()
     * 使用CopyOnWriteArrayList
     */
    public static void dealArrayListConcurrent(){
        List<String> list = new Vector<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }

        // 将原有ArrayList变为线程安全的
        List<String> list1 = Collections.synchronizedList(new ArrayList<>());
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                list1.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list1);
            }, String.valueOf(i)).start();
        }

        // 适用于读多写少的业务
        CopyOnWriteArrayList<String> list2 = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                list2.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list2);
            }, String.valueOf(i)).start();
        }
    }

    /**
     * HashSet解决线程安全问题的方法 两种
     * 使用Collections.synchronizedSet()
     * 使用CopyOnWriteArraySet
     */
    public static void dealHashSetConcurrent(){
        Set<String> set = Collections.synchronizedSet(new HashSet<>());
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }

        // 适用于读多写少的业务
        Set<String> set1 = new CopyOnWriteArraySet<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                set1.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set1);
            }, String.valueOf(i)).start();
        }
    }

    /**
     * HashMap解决线程安全问题的方法 三种
     * 使用Hashtable
     * 使用Collections.synchronizedMap()
     * 使用ConcurrentHashMap()
     */
    public static void dealHashMapConcurrent(){
        Map<String, String> stringMap = new Hashtable<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                stringMap.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                System.out.println(stringMap);
            }, String.valueOf(i)).start();
        }

        Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 3));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }

        Map<String, String> map1 = new ConcurrentHashMap<>();
        for (int i = 0; i < 40; i++) {
            new Thread(() ->{
                map1.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 6));
                System.out.println(map1);
            }, String.valueOf(i)).start();
        }
    }
}
